#ifndef vir_queue_cc
#define vir_queue_cc
#include "virqueue.h"
#include "queue.h"


/* 
 * in COPE, each cope output queue maintain a table for packet queue, named
 * virtual queue, this table is keyed by neighbor id and packet type(L or S)
 */

VirQueue::~VirQueue() {

    VirTableIter it = vir_table_.begin();
    for(; it != vir_table_.end(); it ++)
	delete it->second;
    vir_table_.clear();

}

VirQueue::VirQueue () {

}

void VirQueue::show() {
  
    for( int id = 0; id < 6; id++) {

	vir_key_t key;
	vir_key_t key2;
	key.nb_id = id;
	key.type = 'S';
	cout << "~~~~~~~~~~~~~~~~~~~~~~~~node " << id << " S~~~~~~~~~~~~~~~~~~~~~~" << endl;
       
	VirTableIter iter = vir_table_.find(key);
	// not exist this key's entry
	list<Packet*>::iterator it;
	if(iter == vir_table_.end()) {
	    cout<< "No this entry!" << endl;
    
	} else {
	    cout << "the addr is " << iter->second << endl;
	    for(it = iter->second->begin(); it != iter->second->end(); it++) {
		cout << Scheduler::instance().clock()
		     << " " << HDR_CMN(*it)->ptype()
		     << " " << HDR_CMN(*it)->uid_ 
		     << " " << HDR_CMN(*it)->cope_pkt_id()
		     << " " << HDR_CMN(*it)->next_hop()
		     << "|";
	    }
	    cout << endl;
	}
	key2.type = 'L';
	key2.nb_id = id;
	cout << "~~~~~~~~~~~~~~~~~~~~~~~~node " << id << " L~~~~~~~~~~~~~~~~~~~~~~" << endl;
       
	VirTableIter iter2 = vir_table_.find(key2);
	// not exist this key's entry
	if(iter2 == vir_table_.end()) {
	    cout<< "No this entry!" << endl;
	    continue;
	}
	cout << "the addr is " << iter->second << endl;
	for(it = iter2->second->begin(); it != iter2->second->end(); it++) {
	    cout << Scheduler::instance().clock()
		 << " " << HDR_CMN(*it)->ptype()
		 << " " << HDR_CMN(*it)->uid_ 
		 << " " << HDR_CMN(*it)->cope_pkt_id()
		 << " " << HDR_CMN(*it)->next_hop()
		 << "|";
     
	}
	cout << endl;

    }
}
/*
 * rt is used to decide enque tail or head
 */
void VirQueue::enque_vir_pkt(Packet * p, bool rt) {
 
    vir_key_t key;
    key.nb_id = HDR_CMN(p)->next_hop();
    if (HDR_CMN(p)->size() < PACKET_SIZE_THRESHOLD) { //SmallVirQueue

	key.type = 'S';

    } else {

	key.type = 'L';
    }


    VirTableIter iter;
    iter = vir_table_.find(key);

    // not exist this key's entry
    if(iter == vir_table_.end()) {

        list<Packet *> * pkq = new list<Packet *>;
        vir_table_.insert(std::pair<vir_key_t, list<Packet*>* >(key, pkq));
        iter = vir_table_.find(key);

    }
    
    if( rt == false )
	iter->second->push_back(p);	

    else 
	iter->second->push_front(p);
      
}


/* 
 * remove a specific packet, in COPE, we usually remove the head packet
 */
void VirQueue::remove_vir_pkt(Packet * p) {
    
    if(!p || HDR_CMN(p)->next_hop() < 0)
	return;
    vir_key_t key;
    key.nb_id = HDR_CMN(p)->next_hop();

    if (HDR_CMN(p)->size() < PACKET_SIZE_THRESHOLD) { //SmallVirQueue
	key.type = 'S';
    } else {
	key.type = 'L';
    }

    VirTableIter iter;
    iter = vir_table_.find(key);
  
    
    if(iter != vir_table_.end()) {

	list<Packet*>::iterator pit = iter->second->begin();
	while(pit != iter->second->end()) {
	    // if(HDR_CMN(p)->uid_ == 7199)
	    // 	cout << "---uid: " << HDR_CMN(*pit)->uid_ << endl;
	    if(HDR_CMN(*pit)->uid() == HDR_CMN(p)->uid()) {
		iter->second->remove(*pit);
		break;
	    }
	    pit ++;
	}

	if(iter->second->empty()) {
	    delete iter->second;
	    vir_table_.erase(iter);
	    return;
	} 
    }
}


/* 
 * will return null if the specific entry does not exist 
 */
list<Packet*>* VirQueue::get_vir_pktq(int nb_id, char type) {
    vir_key_t key;
    key.nb_id = nb_id;
    key.type = type;
    
    VirTableIter iter = vir_table_.find(key);
    
    if( iter != vir_table_.end() && !iter->second->empty() )
	return iter->second;
 
    return NULL;  
}


#endif
